What is Operation Sticky Gate?

Major League Baseball’s 2021 season has been marked by record breaking statistics. Particularly the record low ERA’s, extremely high spin rates, and a record breaking amount of no-hitters a few months into the season. Baseball is a game many consider boring from lack of action… -avg spin rate prior to June 1st was around 2280 -mention the og steroid era -data from start of season to June 1, and June 1 to July 17, from Baseball Savant. -sinkers and curveballs

Before the Crackdown

For a long time MLB teams had what some would call a gentleman’s agreement over utilizing foreign substances. Initially this started as a way for pitchers to better their grip on the ball when they pitched. Yet, now it’s gotten to the point that the foreign substances are so sticky that instead of just helping the pitchers grip the ball, it’s making the ball stick to their hand for longer, thus increasing the spin rate of the ball and making it harder to hit. As the spin of the ball increases the general location in which the ball is getting thrown is higher, adding to the difficulties hitters are facing. The spin on pitches like the 4-seam fastballs is a back spin, which opposes the downward force of gravity on the ball (think of the term ‘rising fastball’).

The MLB made a decision coming out against foreign substances by stating that starting on June 1st umpires will begin checking for pitchers using foreign substances and on June 16th announced players caught using them will be removed from the game, placed on a 10 game suspension, and fined. Many people have argued that these statements won’t deter pitchers from utilizing foreign substances. Yet many analysts have been saying spin rates going down and batting averages going up. In this notebook we will be examining the affect of the MLB’s new implementation and examining changes with individual players.

All the data included has been provided by Baseball Savant found through utilizing the search feature and Baseball Reference (linked when referenced).

Velocity vs Spin Rate

It’s important to note that generally as increases velocity so does spin rate. In this section we will be comparing pitchers spin rates vs velocities before and after June 1st.

library(ggplot2) ## loading packages
library(ggExtra)
library(dplyr)
library(tidyverse)
library(plotly)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
b4 <-
  read.csv('b4June1.csv')
b4
aft <-
  read.csv('aftJune1st.csv')
aft
b4gr <-
  b4 %>%
  ggplot(aes(x = velocity, y = spin_rate, color = total_pitches)) +
  geom_point(stat = 'identity') +
  xlab('Velocity (mph)') +
  ylab('Spin Rate (rpm)') +
  ggtitle('Spin Rate VS Velocity Prior to June 1st') +
  labs(color = 'Total Pitches')

##using ggExtra package to add histograms to show the distribution of data within the scatterplot
p1 <-
  ggMarginal(b4gr, type = 'histogram')
p1



aftgr <-
  aft %>%
  ggplot(aes(x = velocity, y = spin_rate, color = total_pitches)) +
  geom_point(stat = 'identity') +
  xlab('Velocity (mph)') +
  ylab('Spin Rate (rpm)') +
  ggtitle('Spin Rate VS Velocity After June 1st') +
  labs(color = 'Total Pitches')

p2 <-  
  ggMarginal(aftgr, type = 'histogram')
p2

The graph of the data before June 1st shows that generally pitchers average spin rates are concentrated between 2200 rpm and 2600 rpm and the velocities range from the upper 80s to mid 90s.

The graph of the data following June 1st, displays a higher conglomeration of pitchers with average pitches between 2000 and 2500 rpm and less outliers with spin rates above 2750 rpm. With velocities concentrated between the upper 80’s and lower 90’s and spin rates between 2000 rpm and 2500 rpm.

Upon further inspection of the scatterplot it appears that most of the outliers are darker shaded dots representing pitcher who’ve thrown between 1 and 250 pitches. Because this data is based on averages and smaller sample sizes are generally less representative of the individual. This prompted me to see if there was a difference when if I increased the minimum number of pitches to at least 250.

b4abv <-
  b4%>%
  filter(total_pitches > 249)
b4abv
aftabv <-
  aft%>%
  filter(total_pitches > 249)
aftabv
babvgr <-
  b4abv %>%
  ggplot(aes(x = velocity, y = spin_rate, color = total_pitches)) +
  geom_point(stat = 'identity') +
  xlab('Velocity (mph)') +
  ylab('Spin Rate (rpm)') +
  labs(color = 'Total Pitches',
       title = 'Spin Rate vs Velocity Before June 1st',
       caption = 'For pitchers with over 250 pitches') +
  scale_color_viridis_c()
g1 <-
  ggMarginal(babvgr, type = 'histogram')
g1



afabvgr <-
  aftabv %>%
  ggplot(aes(x = velocity, y = spin_rate, color = total_pitches)) +
  geom_point(stat = 'identity') +
  xlab('Velocity (mph)') +
  ylab('Spin Rate (rpm)') +
  labs(color = 'Total Pitches',
       title = 'Spin Rate vs Velocity After June 1st',
       caption = 'For pitchers with over 250 pitches') +
  scale_color_viridis_c()

k1 <- 
  ggMarginal(afabvgr, type = 'histogram')
k1

Here we can see a more notable difference between average spin rates and velocities. Prior to June 1st we can see that average velocities were generally between the upper 80s and mid 90s, with spin rates ranging between 2100 and 2600 rpm. The extremes included 5 pitchers with spin rates above 2750 rpm and 20 pitchers above 95 mph. In contrast we can see that after June 1st, velocities are concentrated between the mid 80s to lower 90’s and spin rates between 2000 and 2500 rpm. The extremes here now only include 1 pitcher with an average spin rate above 2750 and 3 pitchers above 95 mph. Additionally the frequency distribution of the velocities changed from left skew to a normal distribution. Whereas the frequency distribution of the spin rates went from bi-modal to a normal distribution following June 1st.

Individual Pitcher Changes

In this section we will be examining a change in spin rate, velocity, and overall performance (if any) between specific pitchers: Trevor Bauer, Gerrit Cole, and Garrett Richards.

Trevor Bauer

It’s hard to have any conversation about foreign substances in baseball without mentioning Trevor Bauer. From being someone who initially spoken against foreign substances and once even stating that they could be more powerful than steroids, to now being accused of having the most effective sticky substance combination in the league, Bauer’s name has been brought up a lot. Considering recent events regarding Bauer’s arrest and allegation, the data available is more limited than with other players.

bauer <- ## downloaded from Baseball Savant
  read.csv('bauer advanced stats.csv')
bauer
num <-
  bauer %>%
  group_by(pitch_name) %>%
  summarise(count = n())
num

From this data we can see that during the month of June, Bauer’s most utilized pitches were the fastball, cutter, and slider.

June 28th

tbju28 <-
  bauer %>%
  filter(game_date == '2021-06-28')
tbju28
tb2avgs <- ## finding game averages from the June 28th game
  tbju28 %>%
  select(pitch_name, release_speed, release_spin_rate) %>%
  group_by(pitch_name) %>%
  summarise(avgspeed = mean(release_speed, na.rm = TRUE), avgspin = mean(release_spin_rate, na.rm = TRUE), count = n()) %>%
  arrange(pitch_name)
tb2avgs

From this we can see that Bauer’s fastest average pitches are his sinker, fastball, and changeup. His pitches with the highest spin rates are the knuckle curve, slider, cutter, and fastball, all with spin rates all well above the average spin rate of 2280 rpm.

Bauer’s most utilized pitches this game:

  • Cutter (medium velocity & high spin rate)

  • Slider (low velocity & high spin rate)

  • Fastball (high velocity & spin rate)

note: Bauer’s ERA during this game was 2.59 Baseball Reference

June 6th

tb28gr <-  ## graph depicting Bauer's spin rates by pitch
  tbju28%>%
  ggplot(aes(x = at_bat_number , y = release_spin_rate, color = pitch_name)) +
  geom_line(stat = 'identity')+
  xlab('At Bat Number') +
  ylab('Release Spin Rate') +
  labs(title = "Trevor Bauer's Spin Rate by Pitch Type",
       color = 'Pitch Name',
       caption = 'From his last game on June 28th')
tb6avgs <-
  tbju6%>%
  select(pitch_name, release_speed, release_spin_rate) %>%
  group_by(pitch_name) %>%
  summarise(avgspeed = mean(release_speed, na.rm = TRUE), avgspin = mean(release_spin_rate, na.rm = TRUE), count = n()) %>%
  arrange(pitch_name)
tb6avgs

Here we can see that from Bauer’s June 6th game, the pitches with the highest speed were the fastball, sinker, and changeup. And his pitches with the highest spin rates were the knuckle curveball, slider, cutter, sinker, and fastball, all significantly above league average of 2280 rpm.

Bauer’s most utilized pitches during this game:

  • Fastball (high velocity & high spin rate)
  • Cutter (medium velocity & high spin rate)
  • Slider (low velocity & high spin rate)

note: Bauer’s ERA during from this game was 2.40 Baseball Reference

tb6gr <-    ## depicting Bauer's spin rates by pitch from June 6th
  tbju6%>%
  ggplot(aes(x = at_bat_number , y = release_spin_rate, color = pitch_name)) +
  geom_line(stat = 'identity')+
  xlab('At Bat Number') +
  ylab('Release Spin Rate') +
  labs(title = "Trevor Bauer's Spin Rate by Pitch Type",
       color = 'Pitch Name',
       caption = 'From game pitched on June 6th')
tb6gr



tb28gr <-  ## depicting Bauer's spin rates by pitch from June 28th
  tbju28%>%
  ggplot(aes(x = at_bat_number , y = release_spin_rate, color = pitch_name)) +
  geom_line(stat = 'identity')+
  xlab('At Bat Number') +
  ylab('Release Spin Rate') +
  labs(title = "Trevor Bauer's Spin Rate by Pitch Type",
       color = 'Pitch Name',
       caption = 'From his last game on June 28th')
tb28gr

Here we can see the drastic drop in Bauer’s spin rate between the two games only 22 days apart. During Bauer’s June 6th game, before the League started implementing the 10-day suspension rule, it can be seen that he has several pitches being thrown at above 3000 rpm and with the exception of his changeup’s all of his pitches are rotating above 2500 rpm. Yet, by June 28th, Bauer didn’t have a single pitch with a spin rate above 3000 rpm. In addition to this, Bauer’s ERA during the two games went from 2.40 to 2.59, meaning he was allowing significantly more runs per inning after implementation. When seeing such large drops in spin rates, it can be speculated that the pitcher was utilizing sticky substances.

Bauer’s Sticky Verdict: GUILTY

Gerrit Cole

After this infamous post game interview of Gerrit Cole, I can’t not examine his stats and see if he was stuttering was an admission of guilt or if he was just tired.

gcoledt <-
  read.csv('Gerrit Cole advanced stats.csv')
gcoledt
gccounts <-
  gcoledt %>%
  group_by(pitch_name) %>%
  summarise(count = n())
gccounts

From this we can see that Cole’s most utilized pitch by far is his fastball, followed by his slider, knuckle curve, and changeup. Whereas his sinker is rarely used, only making an appearance 8 times in almost 800 pitches tracked.

gcju3 <-
  gcoledt %>%
  filter(game_date == '2021-06-03')
gcju3
ju3avg <-
  gcju3%>%
  select(pitch_name, release_spin_rate, release_speed) %>%
  group_by(pitch_name) %>%
  summarise(avgspeed = mean(release_speed, na.rm = TRUE), avgspin = mean(release_spin_rate, na.rm = TRUE), count = n()) %>%
  arrange(pitch_name)
ju3avg

We can see that from Cole’s June 3rd game, the pitches with the highest speed were the fastball, sinker, changeup, and slider. And his pitches with the highest spin rates were the knuckle curve, slider, fastball, and sinker, with all being at least 100 rpm above the league average of 2280 rpm.

Cole’s most utilized pitches during this game:

  • Fastball (high velocity & high spin rate)
  • Knuckle Curve (medium velocity & high spin rate)
  • Changeup (high velocity & low spin rate)

note: Cole’s ERA during from this game was 2.26 Baseball Reference

gcjl17 <-
  gcoledt %>%
  filter(game_date == '2021-07-17')
gcjl17
jl17avg <-
  gcjl17 %>%
  group_by(pitch_name) %>%
  select(pitch_name, release_spin_rate, release_speed) %>%
  summarise(avgspin = mean(release_spin_rate, na.rm = TRUE), avgspeed = mean(release_speed, na.rm = TRUE), count = n()) %>%
  arrange(pitch_name)
jl17avg

Here we can see that from Cole’s July 17th game, the pitches with the highest speed were the fastball, changeup, and slider. And his pitches with the highest spin rates were the knuckle curve, slider, and fastball, all still well the league average of 2280 rpm.

Cole’s most utilized pitches during this game:

  • Fastball (high velocity & medium spin rate)
  • Knuckle Curve (medium velocity & high spin rate)
  • Slider (medium velocity & high spin rate)

note: Cole’s ERA during from this game was 2.63 Baseball Reference

gcju3gr <-
  gcju3 %>%
  ggplot(aes(x = at_bat_number, y = release_spin_rate, color = pitch_name)) +
  geom_line(stat = 'identity') +
  xlab('At Bat Number') +
  ylab('Release Spin Rate') +
  labs(title = "Gerrit Cole's Spin Rate by Pitch",
       caption = 'From the game pitched on June 3rd',
       color = 'Pitch Type')+
  scale_color_manual(values = c('4-Seam Fastball' = 'chocolate1',
                                'Changeup' = 'darkgoldenrod1',
                                'Knuckle Curve' = 'darkseagreen3',
                                'Sinker' = 'darkorchid1',
                                'Slider' = 'deepskyblue'))
gcju3gr



gcjl17gr <-
  gcjl17 %>%
  ggplot(aes(x = at_bat_number, y = release_spin_rate, color = pitch_name)) +
  geom_line(stat = 'identity') +
  xlab('Number At Bat') +
  ylab('Release Spin Rate') +
  labs(title = "Gerrit Cole's Spin Rate by Pitch Type",
       caption = 'From the game Cole pitched on July 17th',
       color = 'Pitch Type') +
  scale_color_manual(values = c('4-Seam Fastball' = 'chocolate1',
                                'Changeup' = 'darkgoldenrod1',
                                'Knuckle Curve' = 'darkseagreen3',
                                'Slider' = 'deepskyblue'))
gcjl17gr

When comparing the two graphs the change in Cole’s spin rates isn’t as drastic as Bauer’s. His changeup, fastball, and slider remained relatively similar to what they were during his starts from his games prior to implementation. Additionally, the spin on his curveball increased, nearly reaching 3000 rpm during at bat number 40. His average release velocities also stayed relatively similar. Although his ERA did go up by 0.4, which is a high increase to incur within a month and a half.

Cole’s Sticky Verdict: uh well… (probably) NOT GUILTY

Garrett Richards

grichdt <-  ## Garrett Richards data from Baseball Savant
  read.csv('Garrett Richards advanced stats.csv')
grichdt
grjul9 <-  ## filtering the data from Garrett Richard's most recent game
  grichdt %>%
  filter(game_date == '2021-07-09')
grjul9
jul19avgs <-
  grjul9%>%
  select(pitch_name, release_spin_rate, release_speed) %>%
  group_by(pitch_name) %>%
  summarise(avgspeed = mean(release_speed, na.rm = TRUE), avgspin = mean(release_spin_rate, na.rm = TRUE), count = n())
jul19avgs
grmay8 <-  ## filtering the data from Garrett Richard's most recent game
  grichdt %>%
  filter(game_date == '2021-05-08')
grmay8
may8avgs <-
  grmay8%>%
  select(release_spin_rate, release_speed, pitch_name) %>%
  group_by(pitch_name) %>%
  summarise(avgspeed = mean(release_speed, na.rm = TRUE), avgspin = mean(release_spin_rate, na.rm = TRUE), count = n())
may8avgs
grjul9gr <-
  grjul9 %>%
  ggplot(aes(x = at_bat_number, y = release_spin_rate, color = pitch_name)) +
  geom_line(stat = 'identity') +
  #geom_point() +
  xlab('At Bat Number') +
  ylab('Release Spin Rate') +
  labs(title = 'Gerritt Richards Spin Rate by Pitch',
       caption = 'For game pitched on July 7th',
       color = 'Pitch Type')
grjul9gr

Richards’ Sticky Verdict:

LS0tCmF1dGhvcjogTW9qaXNvbHV3YSAoSmlzbykgQXdlCnRpdGxlOiAiT3BlcmF0aW9uIFN0aWNreSBHYXRlIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFdoYXQgaXMgT3BlcmF0aW9uIFN0aWNreSBHYXRlPwoKTWFqb3IgTGVhZ3VlIEJhc2ViYWxsJ3MgMjAyMSBzZWFzb24gaGFzIGJlZW4gbWFya2VkIGJ5IHJlY29yZCBicmVha2luZyBzdGF0aXN0aWNzLiBQYXJ0aWN1bGFybHkgdGhlIHJlY29yZCBsb3cgRVJBJ3MsIGV4dHJlbWVseSBoaWdoIHNwaW4gcmF0ZXMsIGFuZCBhIHJlY29yZCBicmVha2luZyBhbW91bnQgb2Ygbm8taGl0dGVycyBhIGZldyBtb250aHMgaW50byB0aGUgc2Vhc29uLiBCYXNlYmFsbCBpcyBhIGdhbWUgbWFueSBjb25zaWRlciBib3JpbmcgZnJvbSBsYWNrIG9mIGFjdGlvbi4uLgotYXZnIHNwaW4gcmF0ZSBwcmlvciB0byBKdW5lIDFzdCB3YXMgYXJvdW5kIDIyODAKLW1lbnRpb24gdGhlIG9nIHN0ZXJvaWQgZXJhCi1kYXRhIGZyb20gc3RhcnQgb2Ygc2Vhc29uIHRvIEp1bmUgMSwgYW5kIEp1bmUgMSB0byBKdWx5IDE3LCBmcm9tIEJhc2ViYWxsIFNhdmFudC4KLXNpbmtlcnMgYW5kIGN1cnZlYmFsbHMKCiMgQmVmb3JlIHRoZSBDcmFja2Rvd24KCkZvciBhIGxvbmcgdGltZSBNTEIgdGVhbXMgaGFkIHdoYXQgc29tZSB3b3VsZCBjYWxsIGEgZ2VudGxlbWFuJ3MgYWdyZWVtZW50IG92ZXIgdXRpbGl6aW5nIGZvcmVpZ24gc3Vic3RhbmNlcy4gSW5pdGlhbGx5IHRoaXMgc3RhcnRlZCBhcyBhIHdheSBmb3IgcGl0Y2hlcnMgdG8gYmV0dGVyIHRoZWlyIGdyaXAgb24gdGhlIGJhbGwgd2hlbiB0aGV5IHBpdGNoZWQuIFlldCwgbm93IGl0J3MgZ290dGVuIHRvIHRoZSBwb2ludCB0aGF0IHRoZSBmb3JlaWduIHN1YnN0YW5jZXMgYXJlIHNvIHN0aWNreSB0aGF0IGluc3RlYWQgb2YganVzdCBoZWxwaW5nIHRoZSBwaXRjaGVycyBncmlwIHRoZSBiYWxsLCBpdCdzIG1ha2luZyB0aGUgYmFsbCBzdGljayB0byB0aGVpciBoYW5kIGZvciBsb25nZXIsIHRodXMgaW5jcmVhc2luZyB0aGUgc3BpbiByYXRlIG9mIHRoZSBiYWxsIGFuZCBtYWtpbmcgaXQgaGFyZGVyIHRvIGhpdC4gQXMgdGhlIHNwaW4gb2YgdGhlIGJhbGwgaW5jcmVhc2VzIHRoZSBnZW5lcmFsIGxvY2F0aW9uIGluIHdoaWNoIHRoZSBiYWxsIGlzIGdldHRpbmcgdGhyb3duIGlzIGhpZ2hlciwgYWRkaW5nIHRvIHRoZSBkaWZmaWN1bHRpZXMgaGl0dGVycyBhcmUgZmFjaW5nLiBUaGUgc3BpbiBvbiBwaXRjaGVzIGxpa2UgdGhlIDQtc2VhbSBmYXN0YmFsbHMgaXMgYSBiYWNrIHNwaW4sIHdoaWNoIG9wcG9zZXMgdGhlIGRvd253YXJkIGZvcmNlIG9mIGdyYXZpdHkgb24gdGhlIGJhbGwgKHRoaW5rIG9mIHRoZSB0ZXJtICdyaXNpbmcgZmFzdGJhbGwnKS4gCgpUaGUgTUxCIG1hZGUgYSBkZWNpc2lvbiBjb21pbmcgb3V0IGFnYWluc3QgZm9yZWlnbiBzdWJzdGFuY2VzIGJ5IHN0YXRpbmcgdGhhdCBzdGFydGluZyBvbiBKdW5lIDFzdCB1bXBpcmVzIHdpbGwgYmVnaW4gY2hlY2tpbmcgZm9yIHBpdGNoZXJzIHVzaW5nIGZvcmVpZ24gc3Vic3RhbmNlcyBhbmQgb24gSnVuZSAxNnRoIGFubm91bmNlZCBwbGF5ZXJzIGNhdWdodCB1c2luZyB0aGVtIHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSBnYW1lLCBwbGFjZWQgb24gYSAxMCBnYW1lIHN1c3BlbnNpb24sIGFuZCBmaW5lZC4gTWFueSBwZW9wbGUgaGF2ZSBhcmd1ZWQgdGhhdCB0aGVzZSBzdGF0ZW1lbnRzIHdvbid0IGRldGVyIHBpdGNoZXJzIGZyb20gdXRpbGl6aW5nIGZvcmVpZ24gc3Vic3RhbmNlcy4gWWV0IG1hbnkgYW5hbHlzdHMgaGF2ZSBiZWVuIHNheWluZyBzcGluIHJhdGVzIGdvaW5nIGRvd24gYW5kIGJhdHRpbmcgIGF2ZXJhZ2VzIGdvaW5nIHVwLiBJbiB0aGlzIG5vdGVib29rIHdlIHdpbGwgYmUgZXhhbWluaW5nIHRoZSBhZmZlY3Qgb2YgdGhlIE1MQidzIG5ldyBpbXBsZW1lbnRhdGlvbiBhbmQgZXhhbWluaW5nIGNoYW5nZXMgd2l0aCBpbmRpdmlkdWFsIHBsYXllcnMuCgpBbGwgdGhlIGRhdGEgaW5jbHVkZWQgaGFzIGJlZW4gcHJvdmlkZWQgYnkgQmFzZWJhbGwgU2F2YW50IGZvdW5kIHRocm91Z2ggdXRpbGl6aW5nIHRoZSBzZWFyY2ggZmVhdHVyZSBhbmQgQmFzZWJhbGwgUmVmZXJlbmNlIChsaW5rZWQgd2hlbiByZWZlcmVuY2VkKS4KCgoKIyMgVmVsb2NpdHkgdnMgU3BpbiBSYXRlCgpJdCdzIGltcG9ydGFudCB0byBub3RlIHRoYXQgZ2VuZXJhbGx5IGFzIGluY3JlYXNlcyB2ZWxvY2l0eSBzbyBkb2VzIHNwaW4gcmF0ZS4gSW4gdGhpcyBzZWN0aW9uIHdlIHdpbGwgYmUgY29tcGFyaW5nIHBpdGNoZXJzIHNwaW4gcmF0ZXMgdnMgdmVsb2NpdGllcyBiZWZvcmUgYW5kIGFmdGVyIEp1bmUgMXN0LgoKCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKSAjIyBsb2FkaW5nIHBhY2thZ2VzCmxpYnJhcnkoZ2dFeHRyYSkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocGxvdGx5KQpgYGAKCgoKYGBge3J9CmI0IDwtCiAgcmVhZC5jc3YoJ2I0SnVuZTEuY3N2JykKYjQKYGBgCgoKIApgYGB7cn0KYWZ0IDwtCiAgcmVhZC5jc3YoJ2FmdEp1bmUxc3QuY3N2JykKYWZ0CmBgYAoKCmBgYHtyfQpiNGdyIDwtCiAgYjQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdmVsb2NpdHksIHkgPSBzcGluX3JhdGUsIGNvbG9yID0gdG90YWxfcGl0Y2hlcykpICsKICBnZW9tX3BvaW50KHN0YXQgPSAnaWRlbnRpdHknKSArCiAgeGxhYignVmVsb2NpdHkgKG1waCknKSArCiAgeWxhYignU3BpbiBSYXRlIChycG0pJykgKwogIGdndGl0bGUoJ1NwaW4gUmF0ZSBWUyBWZWxvY2l0eSBQcmlvciB0byBKdW5lIDFzdCcpICsKICBsYWJzKGNvbG9yID0gJ1RvdGFsIFBpdGNoZXMnKQoKIyN1c2luZyBnZ0V4dHJhIHBhY2thZ2UgdG8gYWRkIGhpc3RvZ3JhbXMgdG8gc2hvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIGRhdGEgd2l0aGluIHRoZSBzY2F0dGVycGxvdApwMSA8LQogIGdnTWFyZ2luYWwoYjRnciwgdHlwZSA9ICdoaXN0b2dyYW0nKQpwMQoKCmFmdGdyIDwtCiAgYWZ0ICU+JQogIGdncGxvdChhZXMoeCA9IHZlbG9jaXR5LCB5ID0gc3Bpbl9yYXRlLCBjb2xvciA9IHRvdGFsX3BpdGNoZXMpKSArCiAgZ2VvbV9wb2ludChzdGF0ID0gJ2lkZW50aXR5JykgKwogIHhsYWIoJ1ZlbG9jaXR5IChtcGgpJykgKwogIHlsYWIoJ1NwaW4gUmF0ZSAocnBtKScpICsKICBnZ3RpdGxlKCdTcGluIFJhdGUgVlMgVmVsb2NpdHkgQWZ0ZXIgSnVuZSAxc3QnKSArCiAgbGFicyhjb2xvciA9ICdUb3RhbCBQaXRjaGVzJykKCnAyIDwtICAKICBnZ01hcmdpbmFsKGFmdGdyLCB0eXBlID0gJ2hpc3RvZ3JhbScpCnAyCmBgYAoKCgpUaGUgZ3JhcGggb2YgdGhlIGRhdGEgYmVmb3JlIEp1bmUgMXN0IHNob3dzIHRoYXQgZ2VuZXJhbGx5IHBpdGNoZXJzIGF2ZXJhZ2Ugc3BpbiByYXRlcyBhcmUgY29uY2VudHJhdGVkIGJldHdlZW4gMjIwMCBycG0gYW5kIDI2MDAgcnBtIGFuZCB0aGUgdmVsb2NpdGllcyByYW5nZSBmcm9tIHRoZSB1cHBlciA4MHMgdG8gbWlkIDkwcy4gCgpUaGUgZ3JhcGggb2YgdGhlIGRhdGEgZm9sbG93aW5nIEp1bmUgMXN0LCBkaXNwbGF5cyBhIGhpZ2hlciBjb25nbG9tZXJhdGlvbiBvZiBwaXRjaGVycyB3aXRoIGF2ZXJhZ2UgcGl0Y2hlcyBiZXR3ZWVuIDIwMDAgYW5kIDI1MDAgcnBtIGFuZCBsZXNzIG91dGxpZXJzIHdpdGggc3BpbiByYXRlcyBhYm92ZSAyNzUwIHJwbS4gV2l0aCB2ZWxvY2l0aWVzIGNvbmNlbnRyYXRlZCBiZXR3ZWVuIHRoZSB1cHBlciA4MCdzIGFuZCBsb3dlciA5MCdzIGFuZCBzcGluIHJhdGVzIGJldHdlZW4gMjAwMCBycG0gYW5kIDI1MDAgcnBtLgoKVXBvbiBmdXJ0aGVyIGluc3BlY3Rpb24gb2YgdGhlIHNjYXR0ZXJwbG90IGl0IGFwcGVhcnMgdGhhdCBtb3N0IG9mIHRoZSBvdXRsaWVycyBhcmUgZGFya2VyIHNoYWRlZCBkb3RzIHJlcHJlc2VudGluZyBwaXRjaGVyIHdobyd2ZSB0aHJvd24gYmV0d2VlbiAxIGFuZCAyNTAgcGl0Y2hlcy4gQmVjYXVzZSB0aGlzIGRhdGEgaXMgYmFzZWQgb24gYXZlcmFnZXMgYW5kIHNtYWxsZXIgc2FtcGxlIHNpemVzIGFyZSBnZW5lcmFsbHkgbGVzcyByZXByZXNlbnRhdGl2ZSBvZiB0aGUgaW5kaXZpZHVhbC4gVGhpcyBwcm9tcHRlZCBtZSB0byBzZWUgaWYgdGhlcmUgd2FzIGEgZGlmZmVyZW5jZSB3aGVuIGlmIEkgaW5jcmVhc2VkIHRoZSBtaW5pbXVtIG51bWJlciBvZiBwaXRjaGVzIHRvIGF0IGxlYXN0IDI1MC4KCgpgYGB7cn0KYjRhYnYgPC0KICBiNCU+JQogIGZpbHRlcih0b3RhbF9waXRjaGVzID4gMjQ5KQpiNGFidgpgYGAKCmBgYHtyfQphZnRhYnYgPC0KICBhZnQlPiUKICBmaWx0ZXIodG90YWxfcGl0Y2hlcyA+IDI0OSkKYWZ0YWJ2CmBgYAoKCgoKYGBge3J9CmJhYnZnciA8LQogIGI0YWJ2ICU+JQogIGdncGxvdChhZXMoeCA9IHZlbG9jaXR5LCB5ID0gc3Bpbl9yYXRlLCBjb2xvciA9IHRvdGFsX3BpdGNoZXMpKSArCiAgZ2VvbV9wb2ludChzdGF0ID0gJ2lkZW50aXR5JykgKwogIHhsYWIoJ1ZlbG9jaXR5IChtcGgpJykgKwogIHlsYWIoJ1NwaW4gUmF0ZSAocnBtKScpICsKICBsYWJzKGNvbG9yID0gJ1RvdGFsIFBpdGNoZXMnLAogICAgICAgdGl0bGUgPSAnU3BpbiBSYXRlIHZzIFZlbG9jaXR5IEJlZm9yZSBKdW5lIDFzdCcsCiAgICAgICBjYXB0aW9uID0gJ0ZvciBwaXRjaGVycyB3aXRoIG92ZXIgMjUwIHBpdGNoZXMnKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkKZzEgPC0KICBnZ01hcmdpbmFsKGJhYnZnciwgdHlwZSA9ICdoaXN0b2dyYW0nKQpnMQoKCmFmYWJ2Z3IgPC0KICBhZnRhYnYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdmVsb2NpdHksIHkgPSBzcGluX3JhdGUsIGNvbG9yID0gdG90YWxfcGl0Y2hlcykpICsKICBnZW9tX3BvaW50KHN0YXQgPSAnaWRlbnRpdHknKSArCiAgeGxhYignVmVsb2NpdHkgKG1waCknKSArCiAgeWxhYignU3BpbiBSYXRlIChycG0pJykgKwogIGxhYnMoY29sb3IgPSAnVG90YWwgUGl0Y2hlcycsCiAgICAgICB0aXRsZSA9ICdTcGluIFJhdGUgdnMgVmVsb2NpdHkgQWZ0ZXIgSnVuZSAxc3QnLAogICAgICAgY2FwdGlvbiA9ICdGb3IgcGl0Y2hlcnMgd2l0aCBvdmVyIDI1MCBwaXRjaGVzJykgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpCgprMSA8LSAKICBnZ01hcmdpbmFsKGFmYWJ2Z3IsIHR5cGUgPSAnaGlzdG9ncmFtJykKazEKCmBgYAoKSGVyZSB3ZSBjYW4gc2VlIGEgbW9yZSBub3RhYmxlIGRpZmZlcmVuY2UgYmV0d2VlbiBhdmVyYWdlIHNwaW4gcmF0ZXMgYW5kIHZlbG9jaXRpZXMuIFByaW9yIHRvIEp1bmUgMXN0IHdlIGNhbiBzZWUgdGhhdCBhdmVyYWdlIHZlbG9jaXRpZXMgd2VyZSBnZW5lcmFsbHkgYmV0d2VlbiB0aGUgdXBwZXIgODBzIGFuZCBtaWQgOTBzLCB3aXRoIHNwaW4gcmF0ZXMgcmFuZ2luZyBiZXR3ZWVuIDIxMDAgYW5kIDI2MDAgcnBtLiBUaGUgZXh0cmVtZXMgaW5jbHVkZWQgNSBwaXRjaGVycyB3aXRoIHNwaW4gcmF0ZXMgYWJvdmUgMjc1MCBycG0gYW5kIDIwIHBpdGNoZXJzIGFib3ZlIDk1IG1waC4gCkluIGNvbnRyYXN0IHdlIGNhbiBzZWUgdGhhdCBhZnRlciBKdW5lIDFzdCwgdmVsb2NpdGllcyBhcmUgY29uY2VudHJhdGVkIGJldHdlZW4gdGhlIG1pZCA4MHMgdG8gbG93ZXIgOTAncyBhbmQgc3BpbiByYXRlcyBiZXR3ZWVuIDIwMDAgYW5kIDI1MDAgcnBtLiBUaGUgZXh0cmVtZXMgaGVyZSBub3cgb25seSBpbmNsdWRlIDEgcGl0Y2hlciB3aXRoIGFuIGF2ZXJhZ2Ugc3BpbiByYXRlIGFib3ZlIDI3NTAgYW5kIDMgcGl0Y2hlcnMgYWJvdmUgOTUgbXBoLiBBZGRpdGlvbmFsbHkgdGhlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gb2YgdGhlIHZlbG9jaXRpZXMgY2hhbmdlZCBmcm9tIGxlZnQgc2tldyB0byBhIG5vcm1hbCBkaXN0cmlidXRpb24uIFdoZXJlYXMgdGhlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gb2YgdGhlIHNwaW4gcmF0ZXMgd2VudCBmcm9tIGJpLW1vZGFsIHRvIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBmb2xsb3dpbmcgSnVuZSAxc3QuCgoKIyBJbmRpdmlkdWFsIFBpdGNoZXIgQ2hhbmdlcwoKSW4gdGhpcyBzZWN0aW9uIHdlIHdpbGwgYmUgZXhhbWluaW5nIGEgY2hhbmdlIGluIHNwaW4gcmF0ZSwgdmVsb2NpdHksIGFuZCBvdmVyYWxsIHBlcmZvcm1hbmNlIChpZiBhbnkpIGJldHdlZW4gc3BlY2lmaWMgcGl0Y2hlcnM6IFRyZXZvciBCYXVlciwgR2Vycml0IENvbGUsIGFuZCBHYXJyZXR0IFJpY2hhcmRzLgoKIyMgVHJldm9yIEJhdWVyCgpJdCdzIGhhcmQgdG8gaGF2ZSBhbnkgY29udmVyc2F0aW9uIGFib3V0IGZvcmVpZ24gc3Vic3RhbmNlcyBpbiBiYXNlYmFsbCB3aXRob3V0IG1lbnRpb25pbmcgVHJldm9yIEJhdWVyLiBGcm9tIGJlaW5nIHNvbWVvbmUgd2hvIGluaXRpYWxseSBzcG9rZW4gYWdhaW5zdCBmb3JlaWduIHN1YnN0YW5jZXMgYW5kIG9uY2UgZXZlbiBzdGF0aW5nIHRoYXQgdGhleSBjb3VsZCBiZSBtb3JlIHBvd2VyZnVsIHRoYW4gc3Rlcm9pZHMsIHRvIG5vdyBiZWluZyBhY2N1c2VkIG9mIGhhdmluZyB0aGUgbW9zdCBlZmZlY3RpdmUgc3RpY2t5IHN1YnN0YW5jZSBjb21iaW5hdGlvbiBpbiB0aGUgbGVhZ3VlLCBCYXVlcidzIG5hbWUgaGFzIGJlZW4gYnJvdWdodCB1cCBhIGxvdC4gQ29uc2lkZXJpbmcgcmVjZW50IGV2ZW50cyByZWdhcmRpbmcgQmF1ZXIncyBhcnJlc3QgYW5kIGFsbGVnYXRpb24sIHRoZSBkYXRhIGF2YWlsYWJsZSBpcyBtb3JlIGxpbWl0ZWQgdGhhbiB3aXRoIG90aGVyIHBsYXllcnMuCgpgYGB7cn0KYmF1ZXIgPC0gIyMgZG93bmxvYWRlZCBmcm9tIEJhc2ViYWxsIFNhdmFudAogIHJlYWQuY3N2KCdiYXVlciBhZHZhbmNlZCBzdGF0cy5jc3YnKQpiYXVlcgpgYGAKCgpgYGB7cn0KbnVtIDwtICAjIyBmaW5kaW5nIGNvdW50cyBvZiBlYWNoIHBpdGNoIHR5cGUKICBiYXVlciAlPiUKICBncm91cF9ieShwaXRjaF9uYW1lKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpCm51bQpgYGAKCgpGcm9tIHRoaXMgZGF0YSB3ZSBjYW4gc2VlIHRoYXQgZHVyaW5nIHRoZSBtb250aCBvZiBKdW5lLCBCYXVlcidzIG1vc3QgdXRpbGl6ZWQgcGl0Y2hlcyB3ZXJlIHRoZSBmYXN0YmFsbCwgY3V0dGVyLCBhbmQgc2xpZGVyLgoKCgojIyMjIEp1bmUgMjh0aAoKYGBge3J9CnRianUyOCA8LQogIGJhdWVyICU+JQogIGZpbHRlcihnYW1lX2RhdGUgPT0gJzIwMjEtMDYtMjgnKQp0Ymp1MjgKYGBgCgpgYGB7cn0KdGIyYXZncyA8LSAjIyBmaW5kaW5nIGdhbWUgYXZlcmFnZXMgZnJvbSB0aGUgSnVuZSAyOHRoIGdhbWUKICB0Ymp1MjggJT4lCiAgc2VsZWN0KHBpdGNoX25hbWUsIHJlbGVhc2Vfc3BlZWQsIHJlbGVhc2Vfc3Bpbl9yYXRlKSAlPiUKICBncm91cF9ieShwaXRjaF9uYW1lKSAlPiUKICBzdW1tYXJpc2UoYXZnc3BlZWQgPSBtZWFuKHJlbGVhc2Vfc3BlZWQsIG5hLnJtID0gVFJVRSksIGF2Z3NwaW4gPSBtZWFuKHJlbGVhc2Vfc3Bpbl9yYXRlLCBuYS5ybSA9IFRSVUUpLCBjb3VudCA9IG4oKSkgJT4lCiAgYXJyYW5nZShwaXRjaF9uYW1lKQp0YjJhdmdzCmBgYAoKCgpGcm9tIHRoaXMgd2UgY2FuIHNlZSB0aGF0IEJhdWVyJ3MgZmFzdGVzdCBhdmVyYWdlIHBpdGNoZXMgYXJlIGhpcyBzaW5rZXIsIGZhc3RiYWxsLCBhbmQgY2hhbmdldXAuIEhpcyBwaXRjaGVzIHdpdGggdGhlIGhpZ2hlc3Qgc3BpbiByYXRlcyBhcmUgdGhlIGtudWNrbGUgY3VydmUsIHNsaWRlciwgY3V0dGVyLCBhbmQgZmFzdGJhbGwsIGFsbCB3aXRoIHNwaW4gcmF0ZXMgYWxsIHdlbGwgYWJvdmUgdGhlIGF2ZXJhZ2Ugc3BpbiByYXRlIG9mIDIyODAgcnBtLgoKQmF1ZXIncyBtb3N0IHV0aWxpemVkIHBpdGNoZXMgdGhpcyBnYW1lOgoKKiBDdXR0ZXIgKG1lZGl1bSB2ZWxvY2l0eSAmIGhpZ2ggc3BpbiByYXRlKQoKKiBTbGlkZXIgKGxvdyB2ZWxvY2l0eSAmIGhpZ2ggc3BpbiByYXRlKQoKKiBGYXN0YmFsbCAoaGlnaCB2ZWxvY2l0eSAmIHNwaW4gcmF0ZSkKCgpub3RlOiBCYXVlcidzIEVSQSBkdXJpbmcgdGhpcyBnYW1lIHdhcyAyLjU5IFtCYXNlYmFsbCBSZWZlcmVuY2VdKGh0dHBzOi8vd3d3LmJhc2ViYWxsLXJlZmVyZW5jZS5jb20vYm94ZXMvTEFOL0xBTjIwMjEwNjI4MC5zaHRtbCkKCiMjIyMgSnVuZSA2dGgKCmBgYHtyfQp0Ymp1NiA8LQogIGJhdWVyICU+JQogIGZpbHRlcihnYW1lX2RhdGUgPT0gJzIwMjEtMDYtMDYnKQp0Ymp1NgpgYGAKCgpgYGB7cn0KdGI2YXZncyA8LQogIHRianU2JT4lCiAgc2VsZWN0KHBpdGNoX25hbWUsIHJlbGVhc2Vfc3BlZWQsIHJlbGVhc2Vfc3Bpbl9yYXRlKSAlPiUKICBncm91cF9ieShwaXRjaF9uYW1lKSAlPiUKICBzdW1tYXJpc2UoYXZnc3BlZWQgPSBtZWFuKHJlbGVhc2Vfc3BlZWQsIG5hLnJtID0gVFJVRSksIGF2Z3NwaW4gPSBtZWFuKHJlbGVhc2Vfc3Bpbl9yYXRlLCBuYS5ybSA9IFRSVUUpLCBjb3VudCA9IG4oKSkgJT4lCiAgYXJyYW5nZShwaXRjaF9uYW1lKQp0YjZhdmdzCmBgYAoKSGVyZSB3ZSBjYW4gc2VlIHRoYXQgZnJvbSBCYXVlcidzIEp1bmUgNnRoIGdhbWUsIHRoZSBwaXRjaGVzIHdpdGggdGhlIGhpZ2hlc3Qgc3BlZWQgd2VyZSB0aGUgZmFzdGJhbGwsIHNpbmtlciwgYW5kIGNoYW5nZXVwLiBBbmQgaGlzIHBpdGNoZXMgd2l0aCB0aGUgaGlnaGVzdCBzcGluIHJhdGVzIHdlcmUgdGhlIGtudWNrbGUgY3VydmViYWxsLCBzbGlkZXIsIGN1dHRlciwgc2lua2VyLCBhbmQgZmFzdGJhbGwsIGFsbCBzaWduaWZpY2FudGx5IGFib3ZlIGxlYWd1ZSBhdmVyYWdlIG9mIDIyODAgcnBtLgoKCkJhdWVyJ3MgbW9zdCB1dGlsaXplZCBwaXRjaGVzIGR1cmluZyB0aGlzIGdhbWU6CgoqIEZhc3RiYWxsIChoaWdoIHZlbG9jaXR5ICYgaGlnaCBzcGluIHJhdGUpCiogQ3V0dGVyIChtZWRpdW0gdmVsb2NpdHkgJiBoaWdoIHNwaW4gcmF0ZSkKKiBTbGlkZXIgKGxvdyB2ZWxvY2l0eSAmIGhpZ2ggc3BpbiByYXRlKQoKCm5vdGU6IEJhdWVyJ3MgRVJBIGR1cmluZyBmcm9tIHRoaXMgZ2FtZSB3YXMgMi40MCBbQmFzZWJhbGwgUmVmZXJlbmNlXShodHRwczovL3d3dy5iYXNlYmFsbC1yZWZlcmVuY2UuY29tL2JveGVzL0FUTC9BVEwyMDIxMDYwNjAuc2h0bWwpCgpgYGB7cn0KdGI2Z3IgPC0gICAgIyMgZGVwaWN0aW5nIEJhdWVyJ3Mgc3BpbiByYXRlcyBieSBwaXRjaCBmcm9tIEp1bmUgNnRoCiAgdGJqdTYlPiUKICBnZ3Bsb3QoYWVzKHggPSBhdF9iYXRfbnVtYmVyICwgeSA9IHJlbGVhc2Vfc3Bpbl9yYXRlLCBjb2xvciA9IHBpdGNoX25hbWUpKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAnaWRlbnRpdHknKSsKICB4bGFiKCdBdCBCYXQgTnVtYmVyJykgKwogIHlsYWIoJ1JlbGVhc2UgU3BpbiBSYXRlJykgKwogIGxhYnModGl0bGUgPSAiVHJldm9yIEJhdWVyJ3MgU3BpbiBSYXRlIGJ5IFBpdGNoIFR5cGUiLAogICAgICAgY29sb3IgPSAnUGl0Y2ggTmFtZScsCiAgICAgICBjYXB0aW9uID0gJ0Zyb20gZ2FtZSBwaXRjaGVkIG9uIEp1bmUgNnRoJykKdGI2Z3IKCgp0YjI4Z3IgPC0gICMjIGRlcGljdGluZyBCYXVlcidzIHNwaW4gcmF0ZXMgYnkgcGl0Y2ggZnJvbSBKdW5lIDI4dGgKICB0Ymp1MjglPiUKICBnZ3Bsb3QoYWVzKHggPSBhdF9iYXRfbnVtYmVyICwgeSA9IHJlbGVhc2Vfc3Bpbl9yYXRlLCBjb2xvciA9IHBpdGNoX25hbWUpKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAnaWRlbnRpdHknKSsKICB4bGFiKCdBdCBCYXQgTnVtYmVyJykgKwogIHlsYWIoJ1JlbGVhc2UgU3BpbiBSYXRlJykgKwogIGxhYnModGl0bGUgPSAiVHJldm9yIEJhdWVyJ3MgU3BpbiBSYXRlIGJ5IFBpdGNoIFR5cGUiLAogICAgICAgY29sb3IgPSAnUGl0Y2ggTmFtZScsCiAgICAgICBjYXB0aW9uID0gJ0Zyb20gaGlzIGxhc3QgZ2FtZSBvbiBKdW5lIDI4dGgnKQp0YjI4Z3IKYGBgCgoKSGVyZSB3ZSBjYW4gc2VlIHRoZSBkcmFzdGljIGRyb3AgaW4gQmF1ZXIncyBzcGluIHJhdGUgYmV0d2VlbiB0aGUgdHdvIGdhbWVzIG9ubHkgMjIgZGF5cyBhcGFydC4gRHVyaW5nIEJhdWVyJ3MgSnVuZSA2dGggZ2FtZSwgYmVmb3JlIHRoZSBMZWFndWUgc3RhcnRlZCBpbXBsZW1lbnRpbmcgdGhlIDEwLWRheSBzdXNwZW5zaW9uIHJ1bGUsIGl0IGNhbiBiZSBzZWVuIHRoYXQgaGUgaGFzIHNldmVyYWwgcGl0Y2hlcyBiZWluZyB0aHJvd24gYXQgYWJvdmUgMzAwMCBycG0gYW5kIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiBoaXMgY2hhbmdldXAncyBhbGwgb2YgaGlzIHBpdGNoZXMgYXJlIHJvdGF0aW5nIGFib3ZlIDI1MDAgcnBtLiBZZXQsIGJ5IEp1bmUgMjh0aCwgQmF1ZXIgZGlkbid0IGhhdmUgYSBzaW5nbGUgcGl0Y2ggd2l0aCBhIHNwaW4gcmF0ZSBhYm92ZSAzMDAwIHJwbS4gSW4gYWRkaXRpb24gdG8gdGhpcywgQmF1ZXIncyBbRVJBXShodHRwczovL2dpdGh1Yi5jb20vamlzb2F3ZS9NTEItRGF0YS1WaXN1YWxpemF0aW9ucy9ibG9iL21haW4vRVJBJTIwRXhwbGFpbmVkLlJtZCkgZHVyaW5nIHRoZSB0d28gZ2FtZXMgd2VudCBmcm9tIDIuNDAgdG8gMi41OSwgbWVhbmluZyBoZSB3YXMgYWxsb3dpbmcgc2lnbmlmaWNhbnRseSBtb3JlIHJ1bnMgcGVyIGlubmluZyBhZnRlciBpbXBsZW1lbnRhdGlvbi4gV2hlbiBzZWVpbmcgc3VjaCBsYXJnZSBkcm9wcyBpbiBzcGluIHJhdGVzLCBpdCBjYW4gYmUgc3BlY3VsYXRlZCB0aGF0IHRoZSBwaXRjaGVyIHdhcyB1dGlsaXppbmcgc3RpY2t5IHN1YnN0YW5jZXMuCgojIyMjIEJhdWVyJ3MgU3RpY2t5IFZlcmRpY3Q6IEdVSUxUWQoKCgojIyBHZXJyaXQgQ29sZQoKQWZ0ZXIgW3RoaXNdKGh0dHBzOi8vdHdpdHRlci5jb20vbXJvYmVyc29uMjIvc3RhdHVzLzE0MDIzNzc2MTQwODY0Njc1ODY/cz0yMCkgaW5mYW1vdXMgcG9zdCBnYW1lIGludGVydmlldyBvZiBHZXJyaXQgQ29sZSwgSSBjYW4ndCBub3QgZXhhbWluZSBoaXMgc3RhdHMgYW5kIHNlZSBpZiBoZSB3YXMgc3R1dHRlcmluZyB3YXMgYW4gYWRtaXNzaW9uIG9mIGd1aWx0IG9yIGlmIGhlIHdhcyBqdXN0IHRpcmVkLgoKCmBgYHtyfQpnY29sZWR0IDwtCiAgcmVhZC5jc3YoJ0dlcnJpdCBDb2xlIGFkdmFuY2VkIHN0YXRzLmNzdicpCmdjb2xlZHQKYGBgCgpgYGB7cn0KZ2Njb3VudHMgPC0KICBnY29sZWR0ICU+JQogIGdyb3VwX2J5KHBpdGNoX25hbWUpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkKZ2Njb3VudHMKYGBgCgoKRnJvbSB0aGlzIHdlIGNhbiBzZWUgdGhhdCBDb2xlJ3MgbW9zdCB1dGlsaXplZCBwaXRjaCBieSBmYXIgaXMgaGlzIGZhc3RiYWxsLCBmb2xsb3dlZCBieSBoaXMgc2xpZGVyLCBrbnVja2xlIGN1cnZlLCBhbmQgY2hhbmdldXAuIFdoZXJlYXMgaGlzIHNpbmtlciBpcyByYXJlbHkgdXNlZCwgb25seSBtYWtpbmcgYW4gYXBwZWFyYW5jZSA4IHRpbWVzIGluIGFsbW9zdCA4MDAgcGl0Y2hlcyB0cmFja2VkLgoKCmBgYHtyfQpnY2p1MyA8LSAgIyMgZGF0YSBmcm9tIENvbGUncyBKdW5lIDNyZCBnYW1lCiAgZ2NvbGVkdCAlPiUKICBmaWx0ZXIoZ2FtZV9kYXRlID09ICcyMDIxLTA2LTAzJykKZ2NqdTMKYGBgCgoKYGBge3J9Cmp1M2F2ZyA8LQogIGdjanUzJT4lCiAgc2VsZWN0KHBpdGNoX25hbWUsIHJlbGVhc2Vfc3Bpbl9yYXRlLCByZWxlYXNlX3NwZWVkKSAlPiUKICBncm91cF9ieShwaXRjaF9uYW1lKSAlPiUKICBzdW1tYXJpc2UoYXZnc3BlZWQgPSBtZWFuKHJlbGVhc2Vfc3BlZWQsIG5hLnJtID0gVFJVRSksIGF2Z3NwaW4gPSBtZWFuKHJlbGVhc2Vfc3Bpbl9yYXRlLCBuYS5ybSA9IFRSVUUpLCBjb3VudCA9IG4oKSkgJT4lCiAgYXJyYW5nZShwaXRjaF9uYW1lKQpqdTNhdmcKYGBgCgoKV2UgY2FuIHNlZSB0aGF0IGZyb20gQ29sZSdzIEp1bmUgM3JkIGdhbWUsIHRoZSBwaXRjaGVzIHdpdGggdGhlIGhpZ2hlc3Qgc3BlZWQgd2VyZSB0aGUgZmFzdGJhbGwsIHNpbmtlciwgY2hhbmdldXAsIGFuZCBzbGlkZXIuIEFuZCBoaXMgcGl0Y2hlcyB3aXRoIHRoZSBoaWdoZXN0IHNwaW4gcmF0ZXMgd2VyZSB0aGUga251Y2tsZSBjdXJ2ZSwgc2xpZGVyLCBmYXN0YmFsbCwgYW5kIHNpbmtlciwgd2l0aCBhbGwgYmVpbmcgYXQgbGVhc3QgMTAwIHJwbSBhYm92ZSB0aGUgbGVhZ3VlIGF2ZXJhZ2Ugb2YgMjI4MCBycG0uCgoKQ29sZSdzIG1vc3QgdXRpbGl6ZWQgcGl0Y2hlcyBkdXJpbmcgdGhpcyBnYW1lOgoKKiBGYXN0YmFsbCAoaGlnaCB2ZWxvY2l0eSAmIGhpZ2ggc3BpbiByYXRlKQoqIEtudWNrbGUgQ3VydmUgKG1lZGl1bSB2ZWxvY2l0eSAmIGhpZ2ggc3BpbiByYXRlKQoqIENoYW5nZXVwIChoaWdoIHZlbG9jaXR5ICYgbG93IHNwaW4gcmF0ZSkKCgpub3RlOiBDb2xlJ3MgRVJBIGR1cmluZyBmcm9tIHRoaXMgZ2FtZSB3YXMgMi4yNiBbQmFzZWJhbGwgUmVmZXJlbmNlXShodHRwczovL3d3dy5iYXNlYmFsbC1yZWZlcmVuY2UuY29tL2JveGVzL05ZQS9OWUEyMDIxMDYwMzAuc2h0bWwpCgoKYGBge3J9CmdjamwxNyA8LQogIGdjb2xlZHQgJT4lCiAgZmlsdGVyKGdhbWVfZGF0ZSA9PSAnMjAyMS0wNy0xNycpCmdjamwxNwpgYGAKCgoKYGBge3J9CmpsMTdhdmcgPC0KICBnY2psMTcgJT4lCiAgZ3JvdXBfYnkocGl0Y2hfbmFtZSkgJT4lCiAgc2VsZWN0KHBpdGNoX25hbWUsIHJlbGVhc2Vfc3Bpbl9yYXRlLCByZWxlYXNlX3NwZWVkKSAlPiUKICBzdW1tYXJpc2UoYXZnc3BpbiA9IG1lYW4ocmVsZWFzZV9zcGluX3JhdGUsIG5hLnJtID0gVFJVRSksIGF2Z3NwZWVkID0gbWVhbihyZWxlYXNlX3NwZWVkLCBuYS5ybSA9IFRSVUUpLCBjb3VudCA9IG4oKSkgJT4lCiAgYXJyYW5nZShwaXRjaF9uYW1lKQpqbDE3YXZnCmBgYAoKCkhlcmUgd2UgY2FuIHNlZSB0aGF0IGZyb20gQ29sZSdzIEp1bHkgMTd0aCBnYW1lLCB0aGUgcGl0Y2hlcyB3aXRoIHRoZSBoaWdoZXN0IHNwZWVkIHdlcmUgdGhlIGZhc3RiYWxsLCBjaGFuZ2V1cCwgYW5kIHNsaWRlci4gQW5kIGhpcyBwaXRjaGVzIHdpdGggdGhlIGhpZ2hlc3Qgc3BpbiByYXRlcyB3ZXJlIHRoZSBrbnVja2xlIGN1cnZlLCBzbGlkZXIsIGFuZCBmYXN0YmFsbCwgYWxsIHN0aWxsIHdlbGwgdGhlIGxlYWd1ZSBhdmVyYWdlIG9mIDIyODAgcnBtLgoKCkNvbGUncyBtb3N0IHV0aWxpemVkIHBpdGNoZXMgZHVyaW5nIHRoaXMgZ2FtZToKCiogRmFzdGJhbGwgKGhpZ2ggdmVsb2NpdHkgJiBtZWRpdW0gc3BpbiByYXRlKQoqIEtudWNrbGUgQ3VydmUgKG1lZGl1bSB2ZWxvY2l0eSAmIGhpZ2ggc3BpbiByYXRlKQoqIFNsaWRlciAobWVkaXVtIHZlbG9jaXR5ICYgaGlnaCBzcGluIHJhdGUpCgpub3RlOiBDb2xlJ3MgRVJBIGR1cmluZyBmcm9tIHRoaXMgZ2FtZSB3YXMgMi42MyBbQmFzZWJhbGwgUmVmZXJlbmNlXShodHRwczovL3d3dy5iYXNlYmFsbC1yZWZlcmVuY2UuY29tL2JveGVzL05ZQS9OWUEyMDIxMDcxNzAuc2h0bWwpCgoKYGBge3J9CmdjanUzZ3IgPC0KICBnY2p1MyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhdF9iYXRfbnVtYmVyLCB5ID0gcmVsZWFzZV9zcGluX3JhdGUsIGNvbG9yID0gcGl0Y2hfbmFtZSkpICsKICBnZW9tX2xpbmUoc3RhdCA9ICdpZGVudGl0eScpICsKICB4bGFiKCdBdCBCYXQgTnVtYmVyJykgKwogIHlsYWIoJ1JlbGVhc2UgU3BpbiBSYXRlJykgKwogIGxhYnModGl0bGUgPSAiR2Vycml0IENvbGUncyBTcGluIFJhdGUgYnkgUGl0Y2giLAogICAgICAgY2FwdGlvbiA9ICdGcm9tIHRoZSBnYW1lIHBpdGNoZWQgb24gSnVuZSAzcmQnLAogICAgICAgY29sb3IgPSAnUGl0Y2ggVHlwZScpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCc0LVNlYW0gRmFzdGJhbGwnID0gJ2Nob2NvbGF0ZTEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDaGFuZ2V1cCcgPSAnZGFya2dvbGRlbnJvZDEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLbnVja2xlIEN1cnZlJyA9ICdkYXJrc2VhZ3JlZW4zJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnU2lua2VyJyA9ICdkYXJrb3JjaGlkMScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1NsaWRlcicgPSAnZGVlcHNreWJsdWUnKSkKZ2NqdTNncgoKCmdjamwxN2dyIDwtCiAgZ2NqbDE3ICU+JQogIGdncGxvdChhZXMoeCA9IGF0X2JhdF9udW1iZXIsIHkgPSByZWxlYXNlX3NwaW5fcmF0ZSwgY29sb3IgPSBwaXRjaF9uYW1lKSkgKwogIGdlb21fbGluZShzdGF0ID0gJ2lkZW50aXR5JykgKwogIHhsYWIoJ051bWJlciBBdCBCYXQnKSArCiAgeWxhYignUmVsZWFzZSBTcGluIFJhdGUnKSArCiAgbGFicyh0aXRsZSA9ICJHZXJyaXQgQ29sZSdzIFNwaW4gUmF0ZSBieSBQaXRjaCBUeXBlIiwKICAgICAgIGNhcHRpb24gPSAnRnJvbSB0aGUgZ2FtZSBDb2xlIHBpdGNoZWQgb24gSnVseSAxN3RoJywKICAgICAgIGNvbG9yID0gJ1BpdGNoIFR5cGUnKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJzQtU2VhbSBGYXN0YmFsbCcgPSAnY2hvY29sYXRlMScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0NoYW5nZXVwJyA9ICdkYXJrZ29sZGVucm9kMScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0tudWNrbGUgQ3VydmUnID0gJ2RhcmtzZWFncmVlbjMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTbGlkZXInID0gJ2RlZXBza3libHVlJykpCmdjamwxN2dyCmBgYAoKV2hlbiBjb21wYXJpbmcgdGhlIHR3byBncmFwaHMgdGhlIGNoYW5nZSBpbiBDb2xlJ3Mgc3BpbiByYXRlcyBpc24ndCBhcyBkcmFzdGljIGFzIEJhdWVyJ3MuIEhpcyBjaGFuZ2V1cCwgZmFzdGJhbGwsIGFuZCBzbGlkZXIgcmVtYWluZWQgcmVsYXRpdmVseSBzaW1pbGFyIHRvIHdoYXQgdGhleSB3ZXJlIGR1cmluZyBoaXMgc3RhcnRzIGZyb20gaGlzIGdhbWVzIHByaW9yIHRvIGltcGxlbWVudGF0aW9uLiBBZGRpdGlvbmFsbHksIHRoZSBzcGluIG9uIGhpcyBjdXJ2ZWJhbGwgaW5jcmVhc2VkLCBuZWFybHkgcmVhY2hpbmcgMzAwMCBycG0gZHVyaW5nIGF0IGJhdCBudW1iZXIgNDAuIEhpcyBhdmVyYWdlIHJlbGVhc2UgdmVsb2NpdGllcyBhbHNvIHN0YXllZCByZWxhdGl2ZWx5IHNpbWlsYXIuIEFsdGhvdWdoIGhpcyBFUkEgZGlkIGdvIHVwIGJ5IDAuNCwgd2hpY2ggaXMgYSBoaWdoIGluY3JlYXNlIHRvIGluY3VyIHdpdGhpbiBhIG1vbnRoIGFuZCBhIGhhbGYuCgoKIyMjIyBDb2xlJ3MgU3RpY2t5IFZlcmRpY3Q6IHVoIHdlbGwuLi4gKHByb2JhYmx5KSBOT1QgR1VJTFRZCgoKIyMgR2FycmV0dCBSaWNoYXJkcwoKCmBgYHtyfQpncmljaGR0IDwtICAjIyBHYXJyZXR0IFJpY2hhcmRzIGRhdGEgZnJvbSBCYXNlYmFsbCBTYXZhbnQKICByZWFkLmNzdignR2FycmV0dCBSaWNoYXJkcyBhZHZhbmNlZCBzdGF0cy5jc3YnKQpncmljaGR0CmBgYAoKCmBgYHtyfQpncmp1bDkgPC0gICMjIGZpbHRlcmluZyB0aGUgZGF0YSBmcm9tIEdhcnJldHQgUmljaGFyZCdzIG1vc3QgcmVjZW50IGdhbWUKICBncmljaGR0ICU+JQogIGZpbHRlcihnYW1lX2RhdGUgPT0gJzIwMjEtMDctMDknKQpncmp1bDkKYGBgCgoKYGBge3J9Cmp1bDE5YXZncyA8LQogIGdyanVsOSU+JQogIHNlbGVjdChwaXRjaF9uYW1lLCByZWxlYXNlX3NwaW5fcmF0ZSwgcmVsZWFzZV9zcGVlZCkgJT4lCiAgZ3JvdXBfYnkocGl0Y2hfbmFtZSkgJT4lCiAgc3VtbWFyaXNlKGF2Z3NwZWVkID0gbWVhbihyZWxlYXNlX3NwZWVkLCBuYS5ybSA9IFRSVUUpLCBhdmdzcGluID0gbWVhbihyZWxlYXNlX3NwaW5fcmF0ZSwgbmEucm0gPSBUUlVFKSwgY291bnQgPSBuKCkpCmp1bDE5YXZncwpgYGAKCgoKYGBge3J9CmdybWF5OCA8LSAgIyMgZmlsdGVyaW5nIHRoZSBkYXRhIGZyb20gUmljaGFyZCdzIE1heSA4dGggZ2FtZQogIGdyaWNoZHQgJT4lCiAgZmlsdGVyKGdhbWVfZGF0ZSA9PSAnMjAyMS0wNS0wOCcpCmdybWF5OApgYGAKCgoKYGBge3J9Cm1heThhdmdzIDwtCiAgZ3JtYXk4JT4lCiAgc2VsZWN0KHJlbGVhc2Vfc3Bpbl9yYXRlLCByZWxlYXNlX3NwZWVkLCBwaXRjaF9uYW1lKSAlPiUKICBncm91cF9ieShwaXRjaF9uYW1lKSAlPiUKICBzdW1tYXJpc2UoYXZnc3BlZWQgPSBtZWFuKHJlbGVhc2Vfc3BlZWQsIG5hLnJtID0gVFJVRSksIGF2Z3NwaW4gPSBtZWFuKHJlbGVhc2Vfc3Bpbl9yYXRlLCBuYS5ybSA9IFRSVUUpLCBjb3VudCA9IG4oKSkKbWF5OGF2Z3MKYGBgCgoKCgpgYGB7cn0KZ3JqdWw5Z3IgPC0KICBncmp1bDkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYXRfYmF0X251bWJlciwgeSA9IHJlbGVhc2Vfc3Bpbl9yYXRlLCBjb2xvciA9IHBpdGNoX25hbWUpKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAnaWRlbnRpdHknKSArCiAgI2dlb21fcG9pbnQoKSArCiAgeGxhYignQXQgQmF0IE51bWJlcicpICsKICB5bGFiKCdSZWxlYXNlIFNwaW4gUmF0ZScpICsKICBsYWJzKHRpdGxlID0gJ0dlcnJpdHQgUmljaGFyZHMgU3BpbiBSYXRlIGJ5IFBpdGNoJywKICAgICAgIGNhcHRpb24gPSAnRm9yIGdhbWUgcGl0Y2hlZCBvbiBKdWx5IDd0aCcsCiAgICAgICBjb2xvciA9ICdQaXRjaCBUeXBlJykKZ3JqdWw5Z3IKYGBgCgoKCgojIyMjICBSaWNoYXJkcycgU3RpY2t5IFZlcmRpY3Q6IAoKCgoKCgo=